package userimpl

import (
	"context"
	"fmt"
	"github.com/pkg/errors"
	"go-caipu/pkg/infra/log"
	"go-caipu/pkg/services/admin/model"
	"go-caipu/pkg/services/admin/sysuser"
	"go-caipu/pkg/services/dto"
	"go-caipu/pkg/util"
	"gorm.io/gorm"
	"time"
)

type store interface {
	GetUserPage(ctx context.Context, cmd sysuser.GetUserPageCommand) (list []model.SysUser, count int64, err error)
	Create(ctx context.Context, user model.SysUser) error
	Update(ctx context.Context, user model.SysUser) error
	Remove(ctx context.Context, cmd sysuser.RemoveUserCommand) error
	UpdateUserPwd(ctx context.Context, cmd sysuser.UpdatePwdCommand) error
	Get(ctx context.Context, cmd sysuser.GetUserCommand) (model.SysUser, error)
	GetUserByUserName(ctx context.Context, username string) (model.SysUser, error)
	UpdateAvatar(ctx context.Context, cmd sysuser.UpdateUserAvatarReq) error
	GetUserByWhere(ctx context.Context, cmd sysuser.GetUserRequest) (result []model.SysUser, err error)
	UpdateUserRole(ctx context.Context, cmd sysuser.UpdateUserRole) error
	UpdateUserBasicInfo(ctx context.Context, cmd sysuser.UpdateUserBasicInfoReq) error

	//UserThird 第三方登录
	UserThird(ctx context.Context, cmd sysuser.UserThirdReq) (int64, bool, error)
	//UserThirdBind 第三方用户绑定
	UserThirdBind(ctx context.Context, cmd sysuser.UserThirdReq) error
	//UserThirdUnBind 第三方用户解绑
	UserThirdUnBind(ctx context.Context, cmd sysuser.UserThirdReq) error
	//GetUserThird 获取第三方用户信息
	GetUserThird(ctx context.Context, userId int64) ([]string, error)
}

type sqlStore struct {
	db     *gorm.DB
	logger log.Logger
}

func ProvideStore(db *gorm.DB) sqlStore {
	return sqlStore{
		db:     db,
		logger: log.New("sysuser.store"),
	}
}
func (ss *sqlStore) GetUserPage(ctx context.Context, cmd sysuser.GetUserPageCommand) (list []model.SysUser, count int64, err error) {
	ExcludedRoleIds := func(cmd sysuser.GetUserPageCommand) func(db *gorm.DB) *gorm.DB {
		return func(db *gorm.DB) *gorm.DB {
			if len(cmd.RoleIds) > 0 {
				return db.Where(" EXISTS (SELECT 1 FROM sys_user_role WHERE sys_user_role.user_id = sys_user.user_id AND sys_user_role.role_id IN (?))", cmd.RoleIds)
			}
			//	排除角色用户
			if len(cmd.NoExcludeRoleUser) > 0 {
				return db.Where("user_id not IN (select user_id  from sys_user_role where role_id IN (?) )", cmd.NoExcludeRoleUser)
			}

			return db
		}
	}
	err = ss.db.Preload("Dept").Preload("Roles").Scopes(
		dto.MakeCondition(cmd.GetNeedSearch()),
		ExcludedRoleIds(cmd),
		dto.Paginate(cmd.GetPageSize(), cmd.GetPageIndex()),
	).Preload("CreateUser").Preload("UpdateUser").Find(&list).Limit(-1).Offset(-1).Count(&count).Error
	return
}
func (ss *sqlStore) GetUserByWhere(ctx context.Context, cmd sysuser.GetUserRequest) (result []model.SysUser, err error) {
	tx := ss.db.Model(&model.SysUser{})
	if cmd.Name != "" {
		//tx.Where("nick_name =?", cmd.Name)
		tx.Where(fmt.Sprintf(" nick_name like '%%%s' ", cmd.Name))
	}
	if len(cmd.RoleIds) > 0 {
		tx.Joins("JOIN sys_user_role sur ON sur.user_id = sys_user.user_id").
			Where("sur.role_id IN (?)", cmd.RoleIds)
	}
	err = tx.Find(&result).Error
	return result, err
}
func (ss *sqlStore) Get(ctx context.Context, cmd sysuser.GetUserCommand) (user model.SysUser, err error) {
	result := ss.db.Preload("Dept").Preload("Roles").Preload("CreateUser").Preload("UpdateUser").Model(&user).First(&user, cmd.UserId)
	if result.Error == gorm.ErrRecordNotFound {
		err = errors.New("sysuser not found")
	}
	var roleId []string
	ss.db.Table("sys_user_role").Where("user_id = ?", cmd.UserId).Pluck("role_id", &roleId)
	user.RoleIds = roleId
	return
}
func (ss *sqlStore) GetUserByUserName(ctx context.Context, username string) (model.SysUser, error) {
	var user model.SysUser
	err := ss.db.Model(&user).Where("username= ?", username).First(&user).Error
	if err != nil {
		return user, err
	}
	var roleId []string
	ss.db.Table("sys_user_role").Where("user_id = ?", user.UserId).Pluck("role_id", &roleId)
	user.RoleIds = roleId
	return user, err
}
func (ss *sqlStore) Create(ctx context.Context, user model.SysUser) (err error) {
	tx := ss.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	var i int64
	err = tx.Model(&user).Where("username= ?", user.Username).Count(&i).Error
	if err != nil {
		return err
	}
	if i > 0 {
		return errors.Errorf("sysuser:%s already", user.Username)
	}
	result := tx.Create(&user)
	//insert user_role
	if len(user.RoleIds) > 0 && result.Error == nil {
		var roles []model.SysUserRole
		for i := 0; i < len(user.RoleIds); i++ {
			roles = append(roles, model.SysUserRole{UserId: user.UserId, RoleId: util.StringToInt64(user.RoleIds[i])})
		}
		err = tx.Create(&roles).Error
	}
	return result.Error
}
func (ss *sqlStore) Update(ctx context.Context, user model.SysUser) error {
	var err error
	tx := ss.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	var existsUser model.SysUser
	db := tx.First(&existsUser, user.UserId)
	if err = db.Error; err != nil {
		return err
	}
	if db.RowsAffected == 0 {
		return errors.Errorf("sysuser:%d not find", user.UserId)
	}
	err = tx.Model(&model.SysUser{}).Where("user_id=?", user.UserId).Omit("password", "salt", "created_at", "created_by").Updates(&user).Error

	if len(user.RoleIds) > 0 && err == nil {
		var roles = []model.SysUserRole{}
		for i := 0; i < len(user.RoleIds); i++ {
			roles = append(roles, model.SysUserRole{UserId: user.UserId, RoleId: util.StringToInt64(user.RoleIds[i])})
		}
		tx.Where("user_id=?", user.UserId).Delete(&model.SysUserRole{})
		err = tx.Create(&roles).Error
	}
	return err
}
func (ss *sqlStore) Remove(ctx context.Context, cmd sysuser.RemoveUserCommand) error {
	var err error
	tx := ss.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	var data model.SysUser
	err = tx.Model(&model.SysUser{}).Delete(&data, cmd.Ids).Error
	tx.Where("user_id IN ?", cmd.Ids).Delete(&model.SysUserRole{})
	tx.Where("user_id IN?", cmd.Ids).Delete(&model.SysUserThird{})
	if err != nil {
		return err
	}
	return nil
}

// UpdateUserPwd 更新用户密码
// 该函数用于更新指定用户的密码和盐值。
// 参数:
// - ctx: 上下文对象，用于控制请求的生命周期。
// - cmd: 更新密码命令，包含用户 ID、新密码和盐值。
// 返回值:
// - error: 如果更新过程中出现错误，则返回错误信息；否则返回 nil。
func (ss *sqlStore) UpdateUserPwd(ctx context.Context, cmd sysuser.UpdatePwdCommand) error {
	return ss.db.Model(&model.SysUser{UserId: cmd.UserId}).Updates(model.SysUser{Password: cmd.NewPassword, Salt: cmd.Salt}).Error
}
func (ss *sqlStore) UpdateAvatar(ctx context.Context, cmd sysuser.UpdateUserAvatarReq) error {
	return ss.db.Model(&model.SysUser{}).Where("user_id = ?", cmd.UpdateBy).Updates(cmd).Error
}
func (ss *sqlStore) UpdateUserBasicInfo(ctx context.Context, cmd sysuser.UpdateUserBasicInfoReq) error {
	return ss.db.Model(&model.SysUser{}).Where("user_id =?", cmd.UserId).Updates(model.SysUser{NickName: cmd.NickName, Sex: cmd.Gender}).Error
}

/**
 */
func (ss *sqlStore) UpdateUserRole(ctx context.Context, cmd sysuser.UpdateUserRole) error {
	var err error
	tx := ss.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	if len(cmd.RoleIds) > 0 {
		var roles = make([]model.SysUserRole, len(cmd.RoleIds))
		for i := 0; i < len(cmd.RoleIds); i++ {
			roles[i] = model.SysUserRole{UserId: cmd.UserId, RoleId: util.StringToInt64(cmd.RoleIds[i])}
		}
		tx.Where("user_id=?", cmd.UserId).Delete(&model.SysUserRole{})
		err = tx.Create(&roles).Error
	}
	user := model.SysUser{}
	user.UpdateBy = util.StringToInt64(cmd.UpdateUserId)
	user.UpdatedAt = time.Now()
	return tx.Model(&model.SysUser{}).Where(" user_id= ?", cmd.UserId).Updates(&user).Error
}

// UserThird 第三方登录
func (ss *sqlStore) UserThird(ctx context.Context, cmd sysuser.UserThirdReq) (int64, bool, error) {
	var data model.SysUserThird
	err := ss.db.Model(&model.SysUserThird{}).Where("third_type=? and third_id=?", cmd.ThirdType, cmd.ThirdId).First(&data).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return 0, false, nil
		}
		return 0, false, err
	}
	return data.UserId, true, nil
}

// UserThirdBind 第三方用户绑定
func (ss *sqlStore) UserThirdBind(ctx context.Context, cmd sysuser.UserThirdReq) error {
	//不存在则插入
	var data model.SysUserThird
	err := ss.db.Model(&model.SysUserThird{}).Where("third_type=? and third_id=? and user_id=?", cmd.ThirdType, cmd.ThirdId, cmd.UserId).First(&data).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return ss.db.Create(&model.SysUserThird{UserId: cmd.UserId, ThirdType: cmd.ThirdType, ThirdId: cmd.ThirdId}).Error
		}
		return err
	}
	//存在则结束
	return nil
}

// UserThirdUnBind 第三方用户解绑
func (ss *sqlStore) UserThirdUnBind(ctx context.Context, cmd sysuser.UserThirdReq) error {
	//删除
	return ss.db.Model(&model.SysUserThird{}).Delete("third_type=? and third_id=? and user_id=?", cmd.ThirdType, cmd.ThirdId, cmd.UserId).Error
}

// GetUserThird 获取第三方用户信息
func (ss *sqlStore) GetUserThird(ctx context.Context, userId int64) ([]string, error) {
	var data []model.SysUserThird
	err := ss.db.Model(&model.SysUserThird{}).Where("user_id=?", userId).Find(&data).Error
	if err != nil {
		return nil, err
	}
	var thirdTypes []string
	for _, item := range data {
		thirdTypes = append(thirdTypes, item.ThirdType)
	}
	return thirdTypes, nil
}
